package com.example.lijuan.myapplication.Service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.location.LocationProviderProxy;
import com.example.lijuan.myapplication.UI.Activity.DashboardApp;
import com.example.lijuan.myapplication.Util.Constants;

/**
 * Service providing the guts of the location polling
 * engine. Uses a WakeLock to ensure the CPU stays on while
 * the location lookup is going on. Handles both successful
 * and timeout conditions.
 * <p>
 * Those wishing to leverage this service should do so via
 * the LocationPoller class.
 */
public class LocationPollerService extends Service {
    public static volatile PowerManager.WakeLock lockStatic = null;

    /**
     * Lazy-initializes the WakeLock when we first use it. We
     * use a partial WakeLock since we only need the CPU on,
     * not the screen.
     */
    private synchronized static PowerManager.WakeLock getLock() {
        if (lockStatic == null) {
            PowerManager mgr = DashboardApp.getPowerManager();

            lockStatic =
                    mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                            Constants.WAKE_LOCK_TAG);
            lockStatic.setReferenceCounted(true);
        }

        return lockStatic;
    }

    /**
     * Called by LocationPoller to trigger a poll for the
     * location. Acquires the WakeLock, then starts the
     * service using the supplied Intent (setting the
     * component so routing always goes to the service).
     */
    public static void requestLocation(Intent intent) {
        Context context = DashboardApp.getContext();

        getLock().acquire();

        intent.setClass(context, LocationPollerService.class);

        context.startService(intent);
    }

    /**
     * Obtain the LocationManager on startup
     */
    @Override
    public void onCreate() {

    }

    /**
     * No-op implementation as required by superclass
     */
    @Override
    public IBinder onBind(Intent i) {
        return (null);
    }

    /**
     * Validates the required extras (EXTRA_PROVIDER and
     * EXTRA_INTENT). If valid, updates the Intent to be
     * broadcast with the application's own package (required
     * to keep the broadcast within this application, so we do
     * not leak security information). Then, forks a
     * PollerThread to do the actual location lookup.
     *
     * @return START_REDELIVER_INTENT to ensure we get the
     * last request again
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        PowerManager.WakeLock lock = getLock();

        if (!lock.isHeld() || (flags & START_FLAG_REDELIVERY) != 0) {
            lock.acquire();
        }

        Intent toBroadcast =
                (Intent) intent.getExtras().get(Constants.EXTRA_INTENT);

        toBroadcast.setPackage(getPackageName());

        new PollerThread(lock, toBroadcast).start();

        return (START_REDELIVER_INTENT);
    }

    /**
     * A WakefulThread subclass that knows how to look up the
     * current location, plus handle the timeout scenario.
     */
    private class PollerThread extends WakefulThread {
        private Intent intentTemplate = null;
        private Runnable onTimeout = null;

        private AMapLocationListener listener = new AMapLocationListener() {

            @Override
            public void onLocationChanged(AMapLocation location) {
                handler.removeCallbacks(onTimeout);
                Intent toBroadcast = new Intent(intentTemplate);
                toBroadcast.putExtra(Constants.EXTRA_LOCATION, location);
                sendBroadcast(toBroadcast);
                quit();
            }

            @Deprecated
            @Override
            public void onLocationChanged(Location location) {
            }

            @Override
            public void onProviderDisabled(String provider) {
                // required for interface, not used
            }

            @Override
            public void onProviderEnabled(String provider) {
                // required for interface, not used
            }

            @Override
            public void onStatusChanged(String provider, int status,
                                        Bundle extras) {
                // required for interface, not used
            }
        };
        private Handler handler = new Handler();

        /**
         * Constructor.
         *
         * @param lock           Already-locked WakeLock
         * @param intentTemplate Intent to be broadcast when location found
         *                       or timeout occurs
         */
        PollerThread(PowerManager.WakeLock lock, Intent intentTemplate) {
            super(lock, "LocationPoller-PollerThread");
            this.intentTemplate = intentTemplate;
        }

        /**
         * Called before the Handler loop begins. Registers a
         * timeout, so we do not wait forever for a location.
         * When a timeout occurs, broadcast an Intent containing
         * an error extra, then terminate the thread. Also,
         * requests a location update from the LocationManager.
         */
        @Override
        protected void onPreExecute() {
            final AMapLocation location = DashboardApp.getLocationManager().getLastKnownLocation(LocationProviderProxy.AMapNetwork);

            // Added in enabled check to even check if there is a provider
            // enabled.
            if (!DashboardApp.getLocationManager().isProviderEnabled(LocationProviderProxy.AMapNetwork)) {
                // There is no provider so fail with the LKL if possible
                Intent toBroadcast = new Intent(intentTemplate);
                toBroadcast.putExtra(Constants.EXTRA_ERROR,
                        "Location Provider disabled!");
                toBroadcast.putExtra(
                        Constants.EXTRA_ERROR_PROVIDER_DISABLED, true);
                toBroadcast.putExtra(Constants.EXTRA_LASTKNOWN, location);
                sendBroadcast(toBroadcast);
                quit();
                return;
            }
//            DashboardApp.getLocationManager().requestLocationData(LocationProviderProxy.AMapNetwork, 10*1000, 15, listener);
            onTimeout = new Runnable() {
                public void run() {
                    Intent toBroadcast = new Intent(intentTemplate);

                    toBroadcast.putExtra(Constants.EXTRA_ERROR, "Timeout!");
                    toBroadcast.putExtra(
                            Constants.EXTRA_ERROR_PROVIDER_DISABLED, false);
                    toBroadcast.putExtra(Constants.EXTRA_LASTKNOWN, location);
                    sendBroadcast(toBroadcast);
                    quit();
                }
            };

            handler.postDelayed(onTimeout, Constants.LOCATION_TIMEOUT);

        }

        /**
         * Called when the Handler loop ends. Removes the
         * location listener.
         */
        @Override
        protected void onPostExecute() {
            DashboardApp.getLocationManager().removeUpdates(listener);

            super.onPostExecute();
        }

        /**
         * Called when the WakeLock is completely unlocked.
         * Stops the service, so everything shuts down.
         */
        @Override
        protected void onUnlocked() {
            stopSelf();
        }
    }
}
